package com.zzk.jpmvvmbase.base

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.zzk.jpmvvmbase.ext.getVmClazz
import java.lang.reflect.ParameterizedType

/**
 * 包含 ViewModel 和 Databind ViewModelActivity基类，把ViewModel 和Databind注入进来了
 *
 * @ProjectName:    JetPackMVVMBase
 * @Package:        com.zzk.jpmvvmbase.base
 * @ClassName:      BaseActivity
 * @Description:
 * @Author:         brilliantzhao
 * @CreateDate:     2021.1.19 14:15
 * @UpdateUser:
 * @UpdateDate:     2021.1.19 14:15
 * @UpdateRemark:
 * @Version:        1.0.0
 */
abstract class BaseActivity<VM : BaseViewModel, DB : ViewDataBinding> : AppCompatActivity(),
    IBaseView {

    //##########################  custom variables start ##########################################

    private var TAG = javaClass.simpleName
    lateinit var mDatabind: DB
    lateinit var mViewModel: VM

    //##########################  custom variables end  ###########################################

    //##########################  override custom metohds start ###################################

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate")
        //页面接受的参数方法
        initParam()
        //私有的初始化Databinding和ViewModel方法
        initViewDataBinding(savedInstanceState)
        //私有的ViewModel与View的契约事件回调逻辑
        registerUiChange()
        //页面数据初始化方法
        initData(savedInstanceState)
        //页面事件监听的方法，一般用于ViewModel层转到View层的事件注册
        initViewObservable()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d(TAG, "onRestart")
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, "onCreate")
    }

    override fun onResume() {
        super.onResume()
        Log.d(TAG, "onCreate")
    }

    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onCreate")
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG, "onCreate")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onCreate")
    }

    //##########################  override custom metohds end  ####################################

    //##########################  override third methods start ####################################

    //##########################  override custom metohds end  ####################################

    //##########################  override third methods start ####################################

    override fun initParam() {}

    override fun initData(savedInstanceState: Bundle?) {}

    override fun initViewObservable() {}

    /**
     * 初始化根布局
     *
     * @return 布局layout的id
     */
    abstract fun initContentView(savedInstanceState: Bundle?): Int

    /**
     * 抽象方法，方便在子类中自定义样式
     */
    abstract fun showLoadingDialog(message: String = "请求网络中...")

    abstract fun dismissLoadingDialog()

    //##########################  override third methods end  #####################################

    //##########################  custom metohds start     ########################################

    /**
     * 跳转页面
     *
     * @param clz 所跳转的目的Activity类
     */
    open fun startActivity(clz: Class<*>?) {
        startActivity(Intent(this, clz))
    }

    /**
     * 跳转页面
     *
     * @param clz    所跳转的目的Activity类
     * @param bundle 跳转所携带的信息
     */
    open fun startActivity(clz: Class<*>?, bundle: Bundle?) {
        val intent = Intent(this, clz)
        if (bundle != null) {
            intent.putExtras(bundle)
        }
        startActivity(intent)
    }

    private fun initViewDataBinding(savedInstanceState: Bundle?) {
        //
        val cls =
            (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[1] as Class<*>
        if (ViewDataBinding::class.java != cls && ViewDataBinding::class.java.isAssignableFrom(cls)) {
            mDatabind = DataBindingUtil.setContentView(this, initContentView(savedInstanceState))
        } else {
            setContentView(initContentView(savedInstanceState))
        }
        //
        mViewModel = ViewModelProvider(this).get(getVmClazz(this))
        //支持LiveData绑定xml，数据改变，UI自动会更新
        mDatabind.lifecycleOwner = this
        //
        lifecycle.addObserver(mViewModel)
    }

    /**
     * 创建ViewModel
     * 使用 androidx viewmodel 2.2.0 后，对 ViewModel 的创建有一些变化
     * 原：ViewModelProviders.of(activity).get(ViewModel.class)
     * 被替换为：ViewModelProvider(activity).get(ViewModel.class)
     * 而使用 ViewModelProvider 创建继承自 AndroidViewModel 的类会报错 Cannot create an instance of class AndroidViewModel
     * 原因是无法创建带参数的构造方法，原因是 ViewModelProvider 默认创建无参的构造方法，如果有参数的构造方法将无法正常创建。
     * 而 AndroidViewModel  需要使用带 application 参数的构造方法创建，解决办法是使用 AndroidViewModelFactory 创建 AndroidViewModel。
     *
     * @param cls
     * @param <T>
     * @return
     */
    private fun createViewModel(): VM {
        return ViewModelProvider(this).get(getVmClazz(this))
    }

    /**
     * 注册UI 事件
     */
    private fun registerUiChange() {
        //显示弹窗
        mViewModel.loadingChange.showDialog.observeInActivity(this, Observer {
            showLoadingDialog(it)
        })
        //关闭弹窗
        mViewModel.loadingChange.dismissDialog.observeInActivity(this, Observer {
            dismissLoadingDialog()
        })
    }

    /**
     * 将非该Activity绑定的ViewModel添加 loading回调 防止出现请求时不显示 loading 弹窗bug
     * @param viewModels Array<out BaseViewModel>
     */
    protected fun addLoadingObserve(vararg viewModels: BaseViewModel) {
        viewModels.forEach { viewModel ->
            //显示弹窗
            viewModel.loadingChange.showDialog.observeInActivity(this, Observer {
                showLoadingDialog(it)
            })
            //关闭弹窗
            viewModel.loadingChange.dismissDialog.observeInActivity(this, Observer {
                dismissLoadingDialog()
            })
        }
    }

    //##########################  custom metohds end   ############################################

}